package com.wechat.gateway.ratelimit;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * 限流配置
 */
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class RateLimitConfig {

    /**
     * 规则名称
     */
    private String ruleName;

    /**
     * API路径模式（支持Ant风格匹配）
     */
    private String pathPattern;

    /**
     * HTTP方法（GET, POST, PUT, DELETE等，null表示所有方法）
     */
    private String method;

    /**
     * 桶容量（最大令牌数）
     */
    private long capacity;

    /**
     * 令牌生成速率（每秒生成的令牌数）
     */
    private double refillRate;

    /**
     * 每个请求消耗的令牌数
     */
    private long tokensPerRequest = 1;

    /**
     * 限流维度（IP、USER、API、GLOBAL）
     */
    private LimitDimension dimension = LimitDimension.API;

    /**
     * 是否启用
     */
    private boolean enabled = true;

    /**
     * 生成桶的键
     */
    public String generateBucketKey(String ip, Long userId, String apiPath) {
        return switch (dimension) {
            case IP -> String.format("%s:ip:%s", ruleName, sanitizeIp(ip));
            case USER -> String.format("%s:user:%s", ruleName, userId != null ? userId : sanitizeIp(ip));
            case API -> String.format("%s:api:%s", ruleName, sanitizePath(apiPath));
            case GLOBAL -> String.format("%s:global", ruleName);
            default -> String.format("%s:api:%s", ruleName, sanitizePath(apiPath));
        };
    }

    /**
     * 清理IP地址，替换特殊字符
     * 将IPv4和IPv6地址中的冒号、点号等替换为下划线
     */
    private String sanitizeIp(String ip) {
        if (ip == null || ip.isEmpty()) {
            return "unknown";
        }

        // 替换IPv6和IPv4中的特殊字符
        return ip.replace(":", "_")
                .replace(".", "_")
                .replace("/", "_")
                .replace("%", "_")
                .replaceAll("[^a-zA-Z0-9_-]", "_");
    }

    /**
     * 清理API路径，替换特殊字符
     */
    private String sanitizePath(String path) {
        if (path == null || path.isEmpty()) {
            return "unknown";
        }

        // 保留路径的可读性，只替换会影响Redis key的字符
        return path.replace(":", "_")
                .replace(" ", "_")
                .replaceAll("[^a-zA-Z0-9/_-]", "_");
    }

    /**
     * 限流维度枚举
     */
    public enum LimitDimension {
        IP, // 基于IP限流
        USER, // 基于用户ID限流
        API, // 基于API限流
        GLOBAL // 全局限流
    }
}